/*
 * DAO.java
 *
 * Created on 8 de agosto de 2007, 05:07 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package ig.formato.dao.abs;

import ig.formato.util.IGFormatoException;
import ig.formato.util.MasterConnection;
import ig.formato.conection.util.IGFormatoConnection;
import java.sql.Connection;
import java.sql.SQLException;

/**
 *
 * @author jsanchez
 * Es una clase basicas que define los metodos basicos que debe tener una implementacion de un dao
 *  
 * Clase encargada de todo lo que tiene que ver con la persistencia de los datos
 * cualquie que sepa del patron Dao debe entender esta clase, Je Je Je
 * 
 */
public abstract class DAO {

    //variables basicas de administracion de la conexion a igformato
    protected java.sql.Connection connectionIgFormato = null;
    protected java.sql.PreparedStatement prep = null;
    protected java.sql.ResultSet resul = null;
    protected java.sql.PreparedStatement prep1 = null;
    protected java.sql.ResultSet resul1 = null;

    /**
     * Busca en la tabla que maneja el DAO un registro por ID
     * @param id
     * @return: el DTO relacionado al DAO
     * @throws ig.formato.util.IGFormatoException: por si algun error
     */
    public abstract Object buscar(Integer id) throws IGFormatoException;
    /**
     * Busca todos los registros que existen la tabla que almistra el DAO
     * @return: un Collection con los DTO's
     * @throws ig.formato.util.IGFormatoException
     */
    public abstract java.util.Collection buscarTodos() throws IGFormatoException;

    /**
     * Almacena el objeto en la DB
     * @param obj: el DTO a almacenar
     * @return: el ID del registro actualizado
     * @throws ig.formato.util.IGFormatoException
     */
    public abstract Integer guardar(Object obj) throws IGFormatoException;

    /**
     * 
     * @param id
     * @throws ig.formato.util.IGFormatoException
     */
    public abstract void eliminar(Integer id) throws IGFormatoException;

    public abstract Object existe(Object obj) throws IGFormatoException;

    /**
     * Retorna una conexion independiente a la base de datos de IGFormato
     */
    public void getConnection() throws IGFormatoException {
        connectionIgFormato = MasterConnection.getMasterConnection().getConnection();
    }

    public Connection getConnectionIgFormato() throws SQLException, ClassNotFoundException, Exception {
        getConnection();
        return connectionIgFormato;
    }

    /**
     * Retorna una conexion independiente a la base de datos especificada
     */
    private java.sql.Connection getConnection(String driver, String url, String usuario, String clave) throws java.sql.SQLException, ClassNotFoundException, Exception {
        Class.forName(driver.trim());
        return java.sql.DriverManager.getConnection(url.trim(), usuario.trim(), clave.trim());
    }

    /**
     * Busca en la tabla parametro el valor de un parametro
     * @param key: es el nombre del parametro en la tabla
     */
    public String getValor(String key) throws java.sql.SQLException, Exception {
        java.sql.PreparedStatement prep3 = null;
        java.sql.ResultSet resul3 = null;
        try {
            prep3 = connectionIgFormato.prepareStatement("SELECT VALOR FROM PARAMETROS WHERE NOMBRE=?");
            prep3.setString(1, key);
            resul3 = prep3.executeQuery();
            if (resul3.next()) {
                return resul3.getString("VALOR");
            }
        } catch (java.sql.SQLException e) {
            throw e;
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                prep3.close();
            } catch (Exception e) {
            }
            try {
                resul3.close();
            } catch (Exception e) {
            }
        }
        return null;
    }

    /**
     * Retorna el numero maximo mas uno de un campo en una tabla X
     * 
     * @param tabla: el nombre de la tabla donde se quiere buscar el id maximo mas 1
     * @return: el numero maximo mas 1
     * @throws java.sql.SQLException: por si alguno error con la conexion
     * @throws java.lang.Exception: por si algun error raro antes de la cnexio a la DB
     */
    public Integer getMaximoId(String tabla) throws SQLException, Exception {
        java.sql.PreparedStatement prep3 = null;
        java.sql.ResultSet resul3 = null;
        try {
            prep3 = connectionIgFormato.prepareStatement("SELECT MAX(ID) FROM " + tabla.trim().toUpperCase());
            resul3 = prep3.executeQuery();
            if (resul3.next()) {
                return resul3.getInt(1) + 1;
            }
        } catch (java.sql.SQLException e) {
            throw e;
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                prep3.close();
            } catch (Exception e) {
            }
            try {
                resul3.close();
            } catch (Exception e) {
            }
        }
        return null;
    }

    /**
     * Retorna una conexion independiente a una fuente de datos configurada en igformato
     * @param id: es el identificador de la conexion
     */
    public java.sql.Connection getConnection(Integer id) throws java.sql.SQLException, ClassNotFoundException, Exception {
        String driver = null;
        String url = null;
        String usuario = null;
        String clave = null;
        java.sql.PreparedStatement prep3 = null;
        java.sql.ResultSet resul3 = null;
        try {
            if (connectionIgFormato == null || connectionIgFormato.isClosed()) {
                this.getConnection();
            }

            prep3 = connectionIgFormato.prepareStatement("SELECT S.DRIVER, S.URL, C.HOST, C.PUERTO, C.BASEDEDATOS ,C.USUARIO, C.CLAVE FROM " +
                    "CONEXION C INNER JOIN SGBD S ON S.ID=C.IDSGBD " +
                    "WHERE C.ID=?");
            prep3.setInt(1, id);
            resul3 = prep3.executeQuery();
            if (resul3.next()) {
                driver = resul3.getString("DRIVER");
                url = resul3.getString("URL");
                String host = resul3.getString("HOST");
                String db = resul3.getString("BASEDEDATOS");
                String puerto = resul3.getString("PUERTO");
                usuario = resul3.getString("USUARIO");
                clave = ig.formato.util.TripleDESEncryption.decrypt(resul3.getString("CLAVE"), "informaciongerencial.com");

                url = url.replace("<host>", host);
                url = url.replace("<HOST>", host);
                url = url.replace("<ip>", host);
                url = url.replace("<IP>", host);

                url = url.replace("<DB>", db);
                url = url.replace("<db>", db);
                url = url.replace("<BD>", db);
                url = url.replace("<bd>", db);
                url = url.replace("<DATABASE>", db);
                url = url.replace("<database>", db);
                url = url.replace("<basededatos>", db);
                url = url.replace("<BASEDEDATOS>", db);

                url = url.replace("<puerto>", puerto);
                url = url.replace("<PUERTO>", puerto);
                url = url.replace("<PORT>", puerto);
                url = url.replace("<port>", puerto);

            } else {
                return null;
            }
            Class.forName(driver.trim());
        } catch (java.sql.SQLException e) {
            throw e;
        } catch (ClassNotFoundException e) {
            throw e;
        } catch (Exception e) {
            throw e;
        } finally {
            try {
                prep3.close();
            } catch (Exception e) {
            }
            try {
                resul3.close();
            } catch (Exception e) {
            }
//            try {
//                connectionIgFormato.close();
//            } catch (Exception e) {
//            }
        }
        if (driver.toUpperCase().trim().equals("JAVA.LANG.OBJECT")) {
            return new IGFormatoConnection(url);
        } else {
            return java.sql.DriverManager.getConnection(url.trim(), usuario.trim(), clave.trim());
        }
    }

    /**
     * Cierra todas la conexiones y statements abriertoa hasta el momento
     * nunca jamas sacara error.
     */
    public void closeAll() {
        //        try{connectionIgFormato.close();}catch(Exception e){}
        try {
            prep.close();
        } catch (Exception e) {
        }
        try {
            resul.close();
        } catch (Exception e) {
        }
        try {
            prep1.close();
        } catch (Exception e) {
        }
        try {
            resul1.close();
        } catch (Exception e) {
        }
    }

    /**
     * hace commit de la tranzacciones echas hasta el moneto de invocarlas.
     * 
     * @throws ig.formato.util.IGFormatoException
     */
    public void commit() throws IGFormatoException {
        MasterConnection.getMasterConnection().commit();
        MasterConnection.getMasterConnection().closeConnectionMaster();
    }

    /**
     * habilita el auto commit de la conecion actual-.
     * 
     * @param b
     * @throws ig.formato.util.IGFormatoException
     */
    public void setAutoCommit(boolean b) throws IGFormatoException {
        getConnection();
        MasterConnection.getMasterConnection().setAutoCommit(b);
    }

    /**
     * hace rollback de cada una de lastransacciones echas hasta el momento de invocarlas
     * 
     * @throws ig.formato.util.IGFormatoException
     */
    public void rollback() throws IGFormatoException {
        MasterConnection.getMasterConnection().rollback();
        MasterConnection.getMasterConnection().closeConnectionMaster();
    }

    /**
     * Es un metodo poderoso que implementa introspeccion para setiar o llenar un objeto ya instanciado
     * los datos con los que se llena se toman desde un resultSet
     * 
     * @param res: es el resultSet desde donde se tomaran los datos
     * @param DTO es el Objeto donde se setiaran los valore 
     * @return: el objeto ya con los valores
     * @throws java.sql.SQLException: por si sucede algo con la conexion
     * @throws java.lang.Exception: otro error inesperado
     */
    public Object getDatos(java.sql.ResultSet res, Object DTO) throws SQLException, Exception {
        java.lang.reflect.Method[] atribC = DTO.getClass().getMethods();
        for (int i = 0; i < atribC.length; i++) {
            if (atribC[i].getName().startsWith("set")) {
                String COLUMNA = atribC[i].getName().substring(3, atribC[i].getName().length());
                Object obj = null;
                try {
                    obj = res.getObject(COLUMNA);
                } catch (Exception e) {/*System.out.println("la columna >"+COLUMNA+"< no existe en la tabla");*/ }
                try {
                    if (obj != null) {
                        if (obj instanceof java.math.BigDecimal) {
                            if (((java.math.BigDecimal) obj).scale() <= 0) {
                                obj = Integer.valueOf(((java.math.BigDecimal) obj).intValue());
                            } else {
                                obj = Double.valueOf(((java.math.BigDecimal) obj).doubleValue());
                            }
                        }
                        atribC[i].invoke(DTO, obj);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("No se pudo invocar el metodos >" + atribC[i] + "< para asignarle el valor :" + obj);
                    throw e;
                }
            }
        }
        return DTO;
    }

    /**
     * Um metodo poderoso implementando introspeccion para colocarle los valores a un 
     * preparestatement, desde un Object
     * 
     * @param pre: es el statement donde se setiaran los valores
     * @param DTO: es el Objeto de donse se tomaran los valores
     * @param nombreColumnasOrdenadas: es una cadena con los nombres de la columnas ordenadas de la misma 
     * forma en que esta en el preparestatement.
     * @throws java.sql.SQLException: por si sucede algun error con la coneccion
     * @throws java.lang.Throwable: por si sucede algun error con la introspeccion
     * @throws java.lang.Exception: por si algun error inesperado.
     */
    public void setDatos(java.sql.PreparedStatement pre, Object DTO, String nombreColumnasOrdenadas) throws SQLException, Throwable, Exception {
        java.lang.reflect.Method[] atribC = DTO.getClass().getMethods();
        String[] campos = nombreColumnasOrdenadas.split(",");
        Object[] obj = new Object[0];
        pre.clearParameters();
        for (int i = 0; i < atribC.length; i++) {
            if (atribC[i].getName().startsWith("get")) {
                String COLUMNA = atribC[i].getName().substring(3, atribC[i].getName().length());
                for (int j = 0; j < campos.length; j++) {
                    if (COLUMNA.trim().toUpperCase().equals(campos[j].trim().toUpperCase())) {
                        pre.setObject(j + 1, atribC[i].invoke(DTO, obj));
                    }
                }
            }
        }
    }
}
